import os
import sys
import time
import subprocess

"""

Usage:
    $ python runner.py
    
    * outputs logfile
    * initiates incremental and full script timer
    * prints basic process output and errors to stdout
    * runs sql scripts and gdal-python elev. lookup
    * calls ogr to output shapefiles
    * zips up shapefiles
    * opens results folder and csv
    
Todo:
    * take area of nearest neighbor veg/fire polygons into account
    * rename class 'lines' to polygons since they are actually buffered polygons
    * work with w48, attribute strahler order, and merge all contiguous reaches (but not across confluences)
    * and thus avoid wrapped/merged confluence linestrings resulting from strahler dissolve.
    * nearest neighbor on all sshaip_splits rather than classes?
    * use elevation lookup to give sshiap data correct flow
    * and thus route lines before splitting, to avoid silly * -1 hack
    * remove mainstems > strahler 4
    * deal with multiple strahlers by reach and reaches that cross hucs
    * add contraints and relationships
    * build a config file using ConfigParser
    * test sending variables to sql scripts
    * refactor to accept arguments of what steps to run
    * add elevation to z value to do 3d lengths
    * write out qgis project file
    * generate OL wms/tilecache
    * find fix for problematic segmentation in strahlers
    * test collecting on raw geometry not text
 
"""
DB_NAME = 'beaver'
DB_USER = 'postgres'
LOG_NAME = 'model_run.log'
SHP_DIR = 'shapefile_outputs'
SHP_OUT = 'huc_three_summary,huc_six_summary,huc_nine_summary,huc_twelve_summary'
SHP_OUT += ',three_final,six_final,nine_final,twelve_final'
CSV_NAME = 'final_summary.csv'

start = time.time()

def get_time(time):
    if time/60 < 1:
      seconds = '%s seconds' % str(time)[:5]
      return seconds
    else:
      minutes = '%s minutes' % str(time/60)[:3]
      return minutes

def elapsed(last_step):
    total = (time.time() - start)
    last = (time.time() - last_step)
    return 'Total time: %s | Last step: %s' % (get_time(total), get_time(last))
    
def color_print(color,text):
    """
    1:red, 2:green, 3:yellow, 4: dark blue, 5:pink, 6:teal blue, 7:white
    """
    print
    print "\033[9%sm%s\033[0m" % (color,text)
    print

def output_error(msg):
    color_print(1,'// -- A problem occured:\n')
    color_print(5,msg)
    color_print(1,'\n// -- Leaving model process...\n')
    sys.exit()
    
def call(command, message=None, timeit=True, sub_process=True):
    if timeit:
        last_step = time.time()
    if message:
        color_print(6,'// -- %s...' % message)
    color_print(4,'Executed shell call: %s' % command)
    if sub_process:
        sub_command = command.split(' ')
        p = subprocess.PIPE
        response = subprocess.Popen(sub_command, stdin=p, stdout=p, stderr=p)
        try:
            msg = response.communicate()[1]
        except:
            pass
        if msg:
            if msg.find('error') > 0 or msg.find('ERROR') > 0 or msg.find('Error') > 0:
                output_error(msg)
            elif msg.find('cannot remove') > 0:
                pass # nothing to delete, no problem
            else:
                print 'Notice: %s' % msg
    else:
        os.system(command)
    if timeit:
        color_print(3,elapsed(last_step))

def call_sql(command, message=None, timeit=True):
    psql_cmd = 'psql -d %s -U %s -f %s -L %s' % (DB_NAME, DB_USER, command, LOG_NAME)
    call(psql_cmd, message, timeit, sub_process=False)

def call_piped(command, message=None, timeit=True):
    pass # todo

def generate_sql(name, name_int):
    path = 'scripts/postgis_step_three' 
    f = open('%s.sql' % path).read()
    s = f.replace('three','%s' % name).replace('gradient <= 3','gradient <= %s' % name_int)
    n_sql = '%s_gradient_class%s.sql' % (path,name_int)
    n = open('%s' % n_sql, 'w')
    n.write(s)
    n.close()
    cmd = 'psql -d beaver -U postgres -f %s -L %s' % (n_sql, LOG_NAME)
    color_print(2,'// -- Autogenerated sql for gradient class %s' % name)
    call(cmd, message='running sql step three for class %s' % name_int)

# db admin
call('dropdb -U postgres beaver', message='dropping db')
call('createdb -U postgres -T template_postgis beaver', message='creating fresh db')
call_sql('scripts/nearest_neighbor_functions.sql',message='loading nearest neighbor and array_accum functions')
call_sql('scripts/upgis_cascadeunion_functions_plpgsql.sql',message='loading pure postgis implmentation of ArcGIS Dissolve from http://postgis.refractions.net/support/wiki/index.php?upgis_cascadeunion')

# Cleanup
call('rm %s' % (LOG_NAME), message='removing log file')
call('rm scripts/elevation_insert.sql', message='clearing elevation sql insert')
call('rm scripts/postgis_step_three_gradient*', message='clearing autogenerated sql for classes above three')
call('rm -f -r %s' % (SHP_DIR), message='deleting shapefile folder')
call('rm shapefile_outputs.zip', message='deleting shapefile zip')
call('rm %s' % CSV_NAME, message='deleting %s' % CSV_NAME)

# data import - everything in UTM - http://spatialreference.org/ref/epsg/26710/
call('shp2pgsql -s 26710 -I -g geometry data_sources/sshiap_utm.shp sshiap_utm | psql beaver -q -U postgres', message ='importing river network data', sub_process=False)
call('shp2pgsql -s 26710 -I -g geometry data_sources/deciduous-forest_utm10.shp forest | psql beaver -q -U postgres', message ='importing riparian forest data', sub_process=False)
call('shp2pgsql -s 26710 -I -g geometry data_sources/fires.shp raw_fires | psql beaver -q -U postgres', message ='importing data', sub_process=False)
call('shp2pgsql -s 26710 -I -g geometry data_sources/Methow_HUC_6_U10Nad27.shp huc6 | psql beaver -q -U postgres', message ='importing data', sub_process=False)
#call('shp2pgsql -s 26710 -I -g geometry data_sources/spch-esu-huc6.shp huc6 | psql beaver -q -U postgres', message ='importing huc6 boundary data', sub_process=False)
#call('shp2pgsql -s 26710 -I -g geometry data_sources/w48-seg_utm10.shp w48 | psql beaver -q -U postgres', message ='importing data', sub_process=False)

# postgis script
call_sql('scripts/postgis_step_one.sql', message='running sql step one - splitting linework, prepping for gradient analysis')

# gdal-python script
call('python scripts/elevation_lookup.py dem=data_sources/methow-tiled-uw.tif', message='running elevation lookup to generate sql insert of elevation data')

# postgis scripts
call_sql('scripts/elevation_insert.sql -q', message='loading elevation table into database')
call_sql('scripts/elevation_update.sql -q', message='loading elevation table into database')
call_sql('scripts/postgis_step_two.sql', message='running sql step two - gradient calculations')
call_sql('scripts/postgis_step_three.sql', message='running sql step three for gradient class three')
generate_sql('six', 6)
generate_sql('nine', 9)
generate_sql('twelve', 12)

# output results csv table
call('psql -d beaver -U postgres -q -f scripts/postgis_step_four.sql -L %s > %s' % (LOG_NAME,CSV_NAME), message='running sql step four - output CSV ("%s") as final summary by class' % CSV_NAME, sub_process=False)

# Shapefile processing
call('mkdir %s' % (SHP_DIR), message='creating shapefile folder')
call("ogr2ogr %s/ PG:'dbname=beaver user=postgres tables=%s'" % (SHP_DIR, SHP_OUT), message='export shapefiles with ogr', sub_process=False)
call('zip shapefile_outputs.zip -r shapefile_outputs/',message='zipping up shapefile output')

color_print(6,'########################### Completed ##############################')

# Open results - mac os only
call('open %s' % SHP_DIR)
call('open %s' % CSV_NAME)
